package eos.dom.server;

import java.util.Vector;

import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;

import org.jdom.Document;
import org.jdom.Element;

import com.google.appengine.api.datastore.Key;

import eos.dom.CardException;

@PersistenceCapable
public class Game {

	@PrimaryKey
	@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
	private Key key;
	@Persistent
	private String host;
	@Persistent
	private Vector<CardStack> stacks;//cartes royaumes + cartes de bases
	@Persistent
	private Vector<Player> players;
	@Persistent
	private String currentPlayer="";

	public Game(String host){
		this.host = host;
		players = new Vector<Player>();
		Player newPlayer = new Player(host);
		players.add(newPlayer);
		currentPlayer="";
	}

	public boolean addNewPlayer(String name){
		Player newPlayer = new Player(name);
		for(Player p:players){
			if(p.getClient().equals(name))
				return false;
		}
		players.add(newPlayer);
		return true;
	}


	public boolean startGame(){
		if(players.size()<2){
			return false;
		}else{
			//Choose the first player
			int first = (int) (Math.random()*players.size());
			currentPlayer = players.get(first).getClient();
			
			
		}
		
		return false;
		
	}

	public void endTurn(){
		if(gameFinished()){
			Player winner = new Player(null);
			int bestScore = -100;
			for(Player p : players){
				int score = p.getVictoryPoints();
				if(score>bestScore){
					winner = p;
					bestScore = score;
				}
				System.out.println("Player "+winner.getClient()+" is the winner!");
			}

		}
	}

	public void nextTurn(){

	}

	public boolean gameFinished(){
		int empty = 0;
		for(CardStack s: stacks){
			if(s.isEmpty()){
				if(s.getId() == CardId.PROVINCE){
					return true;
				}else{
					empty++;
					if (empty == 3) return true;
				}
			}
		}
		return false;
	}

	public void trashCard(Player p, CardId id) throws CardException{
		if(p.hasCardInHand(id)){
			p.removeCardFromHand(id);
		}else{
			throw new CardException("Player hasn't this card, FOOL!");
		}
	}

	public void getNCards(Player p, CardId id, int n) throws CardException{
		CardStack s = getStackOfACard(id);
		if(s == null){
			throw new CardException("Stack of card does not exist ["+id+"]");
		}else if(s.size()<n){
			throw new CardException("Not enough cards left in stack ["+id+"]");
		}else{
			for(int i = 0;i<n;i++){
				s.pop();
				p.getACard(id);
			}
		}
	}

	public void getCardInHand(Player p, CardId id) throws CardException{
		CardStack s = getStackOfACard(id);
		if(s == null){
			throw new CardException("Stack of card does not exist ["+id+"]");
		}else{
			s.pop();
			p.getACardInHand(id);
		}
	}

	public void discardNCards(Player p, int n){
		p.discardNCards(n);
	}

	public void discardAll(Player p){
		p.discardAll();
	}

	public void drawNCards(Player p, int n){
		p.drawNCards(n);
	}

	public int chooseGold(Player p){
		return 0;
	}

	public void chooseNCardToBuy(Player p){

	}

	public void chooseCardWithinGoldRange(Player p, int low, int up){

	}

	private CardStack getStackOfACard(CardId id) {
		for(CardStack s:stacks){
			if(s.getId()==id){
				return s;
			}
		}
		return null;
	}

	@Override
	public String toString() {
		String s = key+"["+host+"]"+players;
		return s;
	}

	public String getHost() {
		return host;
	}

	public void setHost(String host) {
		this.host = host;
	}

	public void prepareCards(int[] cardsChosen) {

		System.out.println(players);
		
		stacks = new Vector<CardStack>();
		//Create Base cards
		stacks.add(new CardStack(CardId.ESTATE));
		stacks.add(new CardStack(CardId.DUCHY));
		stacks.add(new CardStack(CardId.PROVINCE));
		stacks.add(new CardStack(CardId.COPPER));
		stacks.add(new CardStack(CardId.SILVER));
		stacks.add(new CardStack(CardId.GOLD));
		stacks.add(new CardStack(CardId.CURSE));
		stacks.add(new CardStack(CardId.POTION));

		Vector<CardId> cards = new Vector<CardId>();
		cards = fillRandomly(cards,cardsChosen);
		System.out.println(cards);
		//Create Kingdom cards
		for(CardId ids:cards){
			stacks.add(new CardStack(ids));
		}


	}

	private Vector<CardId> fillRandomly(Vector<CardId> cards, int[] cardsChosen) {
		int nbCards = cardsChosen.length;
		Vector<CardId> c = new Vector<CardId>();
		for(int i = 0;i<nbCards;i++){
			c.add(CardId.class.getEnumConstants()[cardsChosen[i]]);
		}
		//Now generate randomly the remaining cards
		while(c.size()<10){
			c.add(generateValidId(c));
		}
		return c;

	}

	private CardId generateValidId(Vector<CardId> c) {
		CardId card = CardId.class.getEnumConstants()[(int) (Math.random()*CardId.values().length)];
		Card test = new Card(card);
		//Test if this is not base, or already in the vector
		while(true){
			card = CardId.class.getEnumConstants()[(int) (Math.random()*CardId.values().length)];
			test = new Card(card);
			for(CardId id:c){
				if(card == id){
					continue;
				}
			}
			if(!test.isBase()){
				return card;
			}
		}
	}

	public Document generateGameData(String name) {
		// TODO Auto-generated method stub
		org.jdom.Document gameInfo = new org.jdom.Document(new Element("Game"));

		System.out.println(this);
		System.out.println(stacks);
		//Kingdom cards
		for(CardStack s:stacks){
			gameInfo.getRootElement().addContent(new Element("Royaume")
			.setAttribute("Nb", ""+s.size())
			.setAttribute("CardId", ""+s.getId().ordinal()));
		}
		Element hand = new Element("Hand");
		for(Player p:players){
			System.out.println(p.moreInfo());
			if(p.getClient().equals(name)){
				//Hand of the player
				int i = 0;
				for(Integer c:p.getHand()){
					hand.addContent(new Element("Card")
					.setAttribute("Index", ""+i)
					.setAttribute("CardId", ""+c));
					i++;
				}

			}else{
				//Other Players hands
				gameInfo.getRootElement().addContent(new Element("Player")
				.setAttribute("NbCard", ""+p.getHand().size())
				.setAttribute("Name", p.getClient()));
			}
			
		}
		gameInfo.getRootElement().addContent(hand);
		//FLAGS
		for(int i = 0;i<players.size();i++){
			//Game started?
			if(!currentPlayer.equals("")){
				gameInfo.getRootElement().addContent(new Element("GameStarted"));
			}
			String playerName = players.get(i).getClient();
			if(playerName.equals(name)){
				//Masquerade?
				if(players.get(i).getMasquerade()){
					gameInfo.getRootElement().addContent(new Element("Masquerade"));
				}
				if(playerName.equals(currentPlayer)){
					//Wait for others?
					if(hasToWait(i)){
						gameInfo.getRootElement().addContent(new Element("HasToWait"));
					}
				}else{
					//Has to discard?
					if(players.get(i).getnCardsToDiscard()!=0){
						gameInfo.getRootElement().addContent(new Element("HasToDiscard"))
						.setAttribute("Nb", ""+players.get(i).getnCardsToDiscard());
					}
					//Has to discard or get curse?
					if(players.get(i).getnCardsToDiscardOrCurse()!=0){
						gameInfo.getRootElement().addContent(new Element("HasToDiscardOrCurse"))
						.setAttribute("Nb", ""+players.get(i).getnCardsToDiscardOrCurse());
					}
				}
			}
		}
		
		
		return gameInfo;
	}

	private boolean hasToWait(int player) {
		for(int i=0;i<players.size();i++){
			if(i!=player){
				if(players.get(i).getnCardsToDiscard()!=0 || players.get(i).getnCardsToDiscardOrCurse()!=0){
					return true;
				}
			}
		}
		return false;
	}

	public Vector<Player> getPlayers() {
		return players;
	}

}
